﻿/*
  Copyright © Alexander G. Bykin, Russia 2009-2010
  This source is subject to the Microsoft Public License (Ms-PL).
  Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  All other rights reserved.
*/

namespace System.Windows.Controls
{
    using System.Windows.Media.Imaging;
    using System.Globalization;

    public class GoogleStaticMap : Control
    {
        #region Constants

        private const string Control_Element_GoogleStaticMapImage = "gsmImage";
        private const string GoogleStaticMapURI = @"http://maps.google.com/maps/api/staticmap";

        #endregion

        #region Dependency Properties

        #region DependencyProperty MapCenter

        /// <summary>
        /// Identifies the MapCenter dependency property.
        /// </summary>
        public static readonly DependencyProperty MapCenterProperty =
            DependencyProperty.Register(
                "MapCenter",
                typeof(MapLocation),
                typeof(GoogleStaticMap),
                new PropertyMetadata(new MapLocation(), OnCenterPropertyChanged));

        /// <summary>
        /// MapCenter property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapCenter value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnCenterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }

            /*string newValue = e.NewValue as string;
            if (!string.IsNullOrEmpty(newValue) && newValue.Contains(","))
            {
                string[] mapLocation = newValue.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                if (mapLocation.Length == 2)
                {
                    control.MapCenter = new MapLocation() { Latitude = System.Convert.ToDouble(mapLocation[0]), Longitude = System.Convert.ToDouble(mapLocation[1]) };
                }
            }*/

            control.MapCenter = e.NewValue as MapLocation;
        }

        #endregion

        #region DependencyProperty MapZoom

        /// <summary>
        /// Identifies the MapZoom dependency property.
        /// </summary>
        public static readonly DependencyProperty MapZoomProperty =
            DependencyProperty.Register(
                "MapZoom",
                typeof(int),
                typeof(GoogleStaticMap),
                new PropertyMetadata(0, OnZoomPropertyChanged));

        /// <summary>
        /// MapZoom property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapZoom value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }

            control.MapZoom = (int)e.NewValue;

        }

        #endregion

        #region DependencyProperty MapFormat

        /// <summary>
        /// Identifies the MapFormat dependency property.
        /// </summary>
        public static readonly DependencyProperty MapFormatProperty =
            DependencyProperty.Register(
                "MapFormat",
                typeof(MapFormat),
                typeof(GoogleStaticMap),
                new PropertyMetadata(MapFormat.PNG8, OnMapFormatPropertyChanged));

        /// <summary>
        /// MapFormat property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapFormat value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnMapFormatPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }

            control.MapFormat = (MapFormat)e.NewValue;

        }

        #endregion

        #region DependencyProperty MapType

        /// <summary>
        /// Identifies the MapType dependency property.
        /// </summary>
        public static readonly DependencyProperty MapTypeProperty =
            DependencyProperty.Register(
                "MapType",
                typeof(MapType),
                typeof(GoogleStaticMap),
                new PropertyMetadata(MapType.Terrain, OnMapTypePropertyChanged));

        /// <summary>
        /// MapType property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapType value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnMapTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }

            control.MapType = (MapType)e.NewValue;

        }

        #endregion

        #region DependencyProperty MapMarkers

        /// <summary>
        /// Identifies the MapMarkers dependency property.
        /// </summary>
        public static readonly DependencyProperty MapMarkersProperty =
            DependencyProperty.Register(
                "MapMarkers",
                typeof(DependencyObjectCollection<MapMarker>),
                typeof(GoogleStaticMap),
                new PropertyMetadata(new DependencyObjectCollection<MapMarker>(), OnMapMarkersPropertyChanged));

        /// <summary>
        /// MapMarkers property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapMarkers value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnMapMarkersPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }
        }

        #endregion

        #region DependencyProperty MapPaths

        /// <summary>
        /// Identifies the MapPaths dependency property.
        /// </summary>
        public static readonly DependencyProperty MapPathsProperty =
            DependencyProperty.Register(
                "MapPaths",
                typeof(DependencyObjectCollection<MapPath>),
                typeof(GoogleStaticMap),
                new PropertyMetadata(new DependencyObjectCollection<MapPath>(), OnMapPathsPropertyChanged));

        /// <summary>
        /// MapPaths property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapPaths value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnMapPathsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }
        }

        #endregion

        #region DependencyProperty MapCustomIcons

        /// <summary>
        /// Identifies the MapCustomIcons dependency property.
        /// </summary>
        public static readonly DependencyProperty MapCustomIconsProperty =
            DependencyProperty.Register(
                "MapCustomIcons",
                typeof(DependencyObjectCollection<MapCustomIcon>),
                typeof(GoogleStaticMap),
                new PropertyMetadata(new DependencyObjectCollection<MapCustomIcon>(), OnMapCustomIconsPropertyChanged));

        /// <summary>
        /// MapCustomIcons property changed handler.
        /// </summary>
        /// <param name="d">GoogleStaticMap that changed its MapCustomIcons value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnMapCustomIconsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GoogleStaticMap control = d as GoogleStaticMap;

            if (control == null)
            {
                return;
            }
        }

        #endregion

        #endregion

        #region Private Properties

        private Image gsmImage { get; set; }

        #endregion

        #region Public Properties

        #region Public Property MapZoom

        public int MapZoom
        {
            get
            {
                return (int)GetValue(MapZoomProperty);
            }

            set
            {
                SetValue(MapZoomProperty, value);
            }
        }

        #endregion

        #region Public Property MapCenter

        public MapLocation MapCenter
        {
            get
            {
                return (MapLocation)GetValue(MapCenterProperty);
            }

            set
            {
                SetValue(MapCenterProperty, value);
            }
        }

        #endregion

        #region Public Property MapFormat

        public MapFormat MapFormat
        {
            get
            {
                return (MapFormat)GetValue(MapFormatProperty);
            }

            set
            {
                SetValue(MapFormatProperty, value);
            }
        }

        #endregion

        #region Public Property MapType

        public MapType MapType
        {
            get
            {
                return (MapType)GetValue(MapTypeProperty);
            }

            set
            {
                SetValue(MapTypeProperty, value);
            }
        }

        #endregion

        #region Public Property MapMarkers

        public DependencyObjectCollection<MapMarker> MapMarkers
        {
            get
            {
                return (DependencyObjectCollection<MapMarker>)GetValue(MapMarkersProperty);
            }
            set
            {
                SetValue(MapMarkersProperty, value);
            }
        }

        #endregion

        #region Public Property MapPaths

        public DependencyObjectCollection<MapPath> MapPaths
        {
            get
            {
                return (DependencyObjectCollection<MapPath>)GetValue(MapPathsProperty);
            }
            set
            {
                SetValue(MapPathsProperty, value);
            }
        }

        #endregion

        #region Public Property MapCustomIcons

        public DependencyObjectCollection<MapCustomIcon> MapCustomIcons
        {
            get
            {
                return (DependencyObjectCollection<MapCustomIcon>)GetValue(MapCustomIconsProperty);
            }
            set
            {
                SetValue(MapCustomIconsProperty, value);
            }
        }

        #endregion

        #endregion

        #region Constructors

        public GoogleStaticMap()
        {
            this.DefaultStyleKey = typeof(GoogleStaticMap);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            #region gsmImage

            if (this.gsmImage != null)
            {
                //this.gsmImage.Loaded -= OnGoogleStaticMapImageLoaded;
            }

            this.gsmImage = GetTemplateChild(Control_Element_GoogleStaticMapImage) as Image;
            //this.gsmImage.Loaded += OnGoogleStaticMapImageLoaded;
            /*Dispatcher.BeginInvoke(() =>
            {
                this.Width = this.ActualWidth;
                this.Height = this.ActualHeight;
                this.LoadMap();
            });*/
            this.LoadMap();

            #endregion
        }

        #endregion

        #region Private Methods

        #region Private Method OnGoogleStaticMapImageLoaded

        private void OnGoogleStaticMapImageLoaded(object sender, RoutedEventArgs e)
        {
            this.LoadMap();
        }

        #endregion

        #region Private Method LoadMap

        private void LoadMap()
        {
            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                return;
            }

            #region Set Center

            string center = string.Empty;
            if (this.MapCenter != null)
            {
                if (string.IsNullOrEmpty(this.MapCenter.Address))
                {
                    center += string.Format("center={0},{1}", this.MapCenter.Latitude.ToString("R", CultureInfo.InvariantCulture), this.MapCenter.Longitude.ToString("R", CultureInfo.InvariantCulture));
                }
                else
                {
                    center += string.Format("center={0}", this.MapCenter.Address);
                }
            }

            #endregion

            #region Set Zoom

            string zoom = string.Empty;
            zoom = string.Format("&zoom={0}", this.MapZoom);

            #endregion

            #region Set Size

            // set size
            string mapSize = string.Format("&size={0}x{1}", 640, 640);
            //string mapSize = string.Format("&size={0}x{1}", this.Width, this.Height);

            #endregion

            #region Set MapType

            string mapType = string.Format("&maptype={0}", this.MapType.ToString().ToLower());
            /*switch (this.MapType)
            {
                case MapType.RoadMap:
                    url += "&maptype=roadmap";
                    break;
                case MapType.Satellite:
                    url += "&maptype=satellite";
                    break;
                case MapType.Hybrid:
                    url += "&maptype=hybrid";
                    break;
                case MapType.Terrain:
                    url += "&maptype=terrain";
                    break;
                default:
                    break;
            }*/

            #endregion

            #region Set MapMarkers

            // set markers
            string mapMarkers = string.Empty;
            foreach (var mapMarker in this.MapMarkers)
            {
                if (string.IsNullOrEmpty(mapMarker.Locations.Address))
                {
                    mapMarkers += string.Format("&markers=color:{0}|label:{1}|{2},{3}", mapMarker.Color, mapMarker.Label, mapMarker.Locations.Latitude, mapMarker.Locations.Longitude);
                }
                else
                {
                    mapMarkers += string.Format("&markers=color:{0}|label:{1}|{2}", mapMarker.Color, mapMarker.Label, mapMarker.Locations.Address);
                }
            }

            #endregion

            #region Set MapCustomIcons

            string mapCustomIcons = string.Empty;
            /*if (this.MapCustomIcons.Locations.Count > 0)
                {
                    mapCustomIcons += "&markers=icon:" + CustomIcons.IconURL;

                    foreach (var location in CustomIcons.Locations)
                    {
                        mapCustomIcons += "|" + (location.Address != null ? location.Address : location.Latitude.ToString() + "," + location.longitude.ToString());
                    }
                }*/

            #endregion

            #region Set MapPaths

            string mapPaths = string.Empty;
            foreach (var path in this.MapPaths)
            {
                if (string.IsNullOrEmpty(path.FillColor))
                {
                    mapPaths += string.Format("&path=color:{0}|weight:{1}" + path.Color, path.Weight);
                }
                else
                {
                    mapPaths += string.Format("&path=color:{0}|weight:{1}|fillcolor:{2}" + path.Color, path.Weight, path.FillColor);
                }

                foreach (var location in path.Locations)
                {
                    if (string.IsNullOrEmpty(location.Address))
                    {
                        mapPaths += string.Format("|{0},{1}", location.Latitude, location.Longitude);
                    }
                    else
                    {
                        mapPaths += string.Format("|{0}", location.Address);
                    }
                }
            }

            #endregion

            #region Load Image

            BitmapImage bitmapImage = new BitmapImage();
            //bitmapImage.DownloadProgress -= OnBitmapImageDownloadProgress;
            //bitmapImage.DownloadProgress += OnBitmapImageDownloadProgress;
            bitmapImage.UriSource = new Uri(string.Format(GoogleStaticMapURI + "?{0}{1}{2}{3}{4}{5}{6}&sensor=false&key=MYKEY", center, zoom, mapSize, mapType, mapMarkers, mapCustomIcons, mapPaths), UriKind.Absolute);
            this.gsmImage.Source = null;
            this.gsmImage.Source = bitmapImage;

            #endregion
        }

        #endregion

        #region Private Method OnBitmapImageDownloadProgress

        private void OnBitmapImageDownloadProgress(object sender, DownloadProgressEventArgs e)
        {
            if (e.Progress == 100)
            {
            }
        }

        #endregion

        #endregion
    }
}
